#include "game_event.h"
#include "game_macros.h"
using namespace CGame::Event;

const char* CGameEvent::CONNECT                  = "connect";
const char* CGameEvent::INIT                     = "init";
const char* CGameEvent::CLOSE                    = "close";

namespace CGame{
namespace Event{

template <typename TYPE, void (TYPE::*onEvent)(EventContext_t*) >  
void __event_cb(int sock, short which, void *arg) 
{     
    // TYPE* This = (TYPE*)arg;     
    // This->onEvent(request);
  EventContext_t* ctx = static_cast<EventContext_t*>(arg);
  ctx->_this->onEvent(ctx);
}
}}

BOOL CGameEventDispatcher::init(){
  // logger->info("%s","Init CGameEventDispatcher.");
  // C_LOG("%s\n","Init CGameEventDispatcher.");
  // _threads = new thread_t[C_MAX_EVENT_THREAD];

  // for(int i = 0;i < C_MAX_EVENT_THREAD;i++){
  //   thread_t t = start();
  //   _threads[i] = t;
  // }

  // for(int i = 0;i < MAX_EVENT_THREAD;i++){
  //   cancel(_threads[i]);
  // }


  return init(g_CGameEV.getBase());
}



BOOL CGameEventDispatcher::init(event_base* evbase){
  _evbase = evbase;
  return TRUE;
}

CGameEventDispatcher::CGameEventDispatcher():_evbase(NULL){

}

CGameEventDispatcher::~CGameEventDispatcher(){}

void CGameEventDispatcher::onEvent(CGame::Event::EventContext_t* ctx){
  // CC_LOG("CGameEventDispatcher","%s","onEvent");

  ListenerMap_t::iterator itr = _listenerMap.find(ctx->_event->getType());
  if(itr != _listenerMap.end()){
    EventHanderList* handlers = itr->second;

    EventHanderList list;
    list.assign(handlers->begin(),handlers->end());

    // memmove(&list,handlers,sizeof(CGameEventHandler) * handlers->size());

    for(EventHanderList::iterator itr3 = list.begin(); itr3 != list.end();itr3++){
      CGameEventHandler &handler = (*itr3);
      handler(ctx->_event);
      if(ctx->_event->_stopPropagation)
        break;
        // std::string
    }
  }
  // delete ctx->_event;
  ctx->_event->release();
  event_free(ctx->_ev);
  delete ctx;
}

void CGameEventDispatcher::removeEventListener(const CGameEvent::Type& type,CGameEventHandler handler){
  doRemoveEventListener(type,handler);
}

void CGameEventDispatcher::doRemoveEventListener(const CGameEvent::Type& type,CGameEventHandler handler){
  ListenerMap_t::iterator itr = _listenerMap.find(type);

  if(itr != _listenerMap.end()){
    EventHanderList* handlers = itr->second;
    EventHanderList::iterator itr3 = handlers->begin();

    while (itr3 != handlers->end())
    {
      CGameEventHandler _handler = (*itr3);
      if(handler == _handler){
        itr3 = handlers->erase(itr3);
      }else itr3++;
    }
    
    
    // for(EventHanderList::iterator itr3 = handlers->begin(); itr3 != handlers->end();itr3++){
    //   CGameEventHandler _handler = (*itr3);
    //   if(handler == _handler){
    //     itr3 = handlers->erase(itr3);
    //   }
    //     // std::string
    // }
  }
}

void CGameEventDispatcher::addEventListener(const CGameEvent::Type& type,CGameEventHandler handler){
  CC_ASSERT(NULL != _evbase,"CGameEventDispatcher","Must init a CGameEventDispatcher first.");
  EventHanderList* listeners = nullptr;

  ListenerMap_t::iterator itr = _listenerMap.find(type);

  if(itr == _listenerMap.end()){
    listeners = new EventHanderList();
    _listenerMap.insert(std::make_pair(type, listeners));
  }else listeners = itr->second;


  listeners->push_back(handler);

}

void CGameEventDispatcher::dispatch(CGameEvent* event){
  CC_ASSERT(NULL != _evbase,"CGameEventDispatcher","Must init a CGameEventDispatcher first.");

  EventContext_t* ctx = new EventContext_t();
  ctx->_this = this;
  ctx->_event = event;
  ctx->_ev = event_new(_evbase, -1, EV_PERSIST, CGame::Event::__event_cb<CGameEventDispatcher,&CGameEventDispatcher::onEvent>, ctx);
  event_add(ctx->_ev, NULL);
  event_active(ctx->_ev,EV_SIGNAL,0);
}


CGameEvent::CGameEvent(const char* type,CGameRef* currentTarget){
  _type = type;
  _currentTarget = currentTarget;
  _currentTarget->retain();
};

void CGameEvent::release(){
  _currentTarget->release();
  CGameRef::release();
}
